<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Travel Assistant | ZenML</title>

    <!-- ZenML Brand Fonts (Fontsource CDN) -->
    <link
      href="https://cdn.jsdelivr.net/npm/@fontsource-variable/inter@5.0.16/index.min.css"
      rel="stylesheet"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.0.16/index.min.css"
      rel="stylesheet"
    />

    <style>
      /* ===== CSS Variables - ZenML Design System ===== */
      :root {
        /* Primary Colors */
        --zenml-purple: #7a3ef4;
        --zenml-purple-dark: #431d93;
        --zenml-purple-light: #e4d8fd;
        --zenml-purple-lighter: #f1ebfe;
        --zenml-purple-mid: #9565f6;

        /* Neutral Colors */
        --text-primary: #0d061d;
        --text-secondary: #6b7280;
        --text-tertiary: #9ca3af;
        --surface-primary: #ffffff;
        --surface-secondary: #f9fafb;
        --surface-tertiary: #f3f4f6;

        /* Semantic Colors */
        --success: #1cbf4a;
        --success-light: #d2f2db;
        --warning: #f98b0a;
        --warning-light: #fff6ea;
        --error: #eb483d;
        --error-light: #fbdad8;

        /* Border Colors */
        --border-moderate: #e5e7eb;
        --border-bold: #6b7280;

        /* Typography */
        --font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
          Roboto, sans-serif;
        --font-mono: "JetBrains Mono", "SF Mono", Monaco, "Courier New",
          monospace;

        /* Spacing Scale (8pt grid) */
        --spacing-xs: 4px;
        --spacing-sm: 8px;
        --spacing-md: 16px;
        --spacing-lg: 24px;
        --spacing-xl: 32px;
        --spacing-2xl: 48px;

        /* Shadows */
        --shadow-subtle: 0 1px 3px rgba(0, 0, 0, 0.1);
        --shadow-standard: 0 2px 8px rgba(0, 0, 0, 0.1);
        --shadow-emphasized: 0 4px 16px rgba(0, 0, 0, 0.15);

        /* Border Radius */
        --radius-sm: 4px;
        --radius-md: 8px;
        --radius-lg: 12px;
        --radius-full: 999px;
      }

      /* ===== Reset & Base Styles ===== */
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: var(--font-ui);
        background: var(--surface-secondary);
        color: var(--text-primary);
        padding: var(--spacing-xl);
        font-size: 16px;
        line-height: 24px;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
      }

      /* ===== Layout ===== */
      .container {
        max-width: 800px;
        margin: 0 auto;
      }

      .card {
        background: var(--surface-primary);
        border: 1px solid var(--border-moderate);
        border-radius: var(--radius-md);
        padding: var(--spacing-lg);
        box-shadow: var(--shadow-standard);
      }

      /* ===== Hero Section ===== */
      .hero {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--spacing-lg);
        margin-bottom: var(--spacing-lg);
        padding-bottom: var(--spacing-lg);
        border-bottom: 1px solid var(--border-moderate);
      }

      .hero-copy {
        flex: 1;
      }

      .title {
        margin: 0 0 var(--spacing-sm) 0;
        font-size: 28px;
        font-weight: 600;
        line-height: 36px;
        color: var(--text-primary);
      }

      .subtitle {
        margin: 0;
        font-size: 16px;
        line-height: 24px;
        color: var(--text-secondary);
      }

      .hero-art svg {
        display: block;
        filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.08));
      }

      /* ===== Section ===== */
      .section {
        margin-top: var(--spacing-lg);
      }

      .section h2 {
        font-size: 20px;
        font-weight: 600;
        line-height: 28px;
        color: var(--text-primary);
        margin-bottom: var(--spacing-md);
      }

      /* ===== Form ===== */
      .form-col {
        display: flex;
        flex-direction: column;
        gap: var(--spacing-sm);
      }

      .input {
        width: 100%;
        min-height: 120px;
        padding: 12px 16px;
        border: 1px solid var(--border-moderate);
        border-radius: var(--radius-md);
        font-family: var(--font-ui);
        font-size: 16px;
        line-height: 24px;
        color: var(--text-primary);
        background: var(--surface-primary);
        transition: border-color 0.2s ease, box-shadow 0.2s ease;
        resize: vertical;
      }

      .input::placeholder {
        color: var(--text-tertiary);
      }

      .input:focus {
        outline: none;
        border-color: var(--zenml-purple);
        box-shadow: 0 0 0 3px rgba(122, 62, 244, 0.1);
      }

      .actions {
        display: flex;
        gap: var(--spacing-sm);
        flex-wrap: wrap;
        align-items: center;
      }

      /* ===== Buttons ===== */
      .btn {
        padding: 12px 24px;
        border: none;
        border-radius: var(--radius-md);
        font-family: var(--font-ui);
        font-size: 14px;
        font-weight: 600;
        line-height: 20px;
        cursor: pointer;
        transition: background-color 0.2s ease, transform 0.1s ease,
          box-shadow 0.2s ease;
      }

      .btn:disabled {
        opacity: 0.4;
        cursor: not-allowed;
      }

      .btn:active:not(:disabled) {
        transform: translateY(1px);
      }

      /* Primary Button */
      .btn:not(.secondary) {
        background: var(--zenml-purple);
        color: var(--surface-primary);
      }

      .btn:not(.secondary):hover:not(:disabled) {
        background: var(--zenml-purple-dark);
        box-shadow: var(--shadow-standard);
      }

      /* Secondary Button */
      .btn.secondary {
        background: var(--surface-primary);
        color: var(--zenml-purple);
        border: 1px solid var(--border-moderate);
      }

      .btn.secondary:hover:not(:disabled) {
        background: var(--surface-tertiary);
      }

      /* Suggestion Chips */
      .chips {
        display: flex;
        flex-wrap: wrap;
        gap: var(--spacing-sm);
        margin-top: var(--spacing-sm);
      }

      .chip {
        display: inline-flex;
        align-items: center;
        padding: 8px 12px;
        border-radius: var(--radius-full);
        background: var(--zenml-purple-lighter);
        color: var(--zenml-purple);
        border: 1px solid var(--zenml-purple-light);
        font-size: 13px;
        line-height: 18px;
        cursor: pointer;
        user-select: none;
        transition: background-color 0.2s ease, border-color 0.2s ease;
      }

      .chip:hover {
        background: #e9ddfe;
        border-color: var(--zenml-purple-mid);
      }

      /* ===== Status Pill ===== */
      .status-pill {
        display: inline-block;
        padding: 6px 12px;
        border-radius: var(--radius-full);
        font-size: 12px;
        font-weight: 600;
        line-height: 18px;
        margin-top: var(--spacing-sm);
      }

      .status-pill.auth-set {
        background: var(--success-light);
        color: var(--success);
      }

      .status-pill.auth-required {
        background: var(--warning-light);
        color: var(--warning);
      }

      /* ===== Messages ===== */
      .message {
        margin-top: var(--spacing-md);
        padding: var(--spacing-md);
        border-radius: var(--radius-md);
        font-size: 14px;
        line-height: 20px;
      }

      .message.info {
        background: var(--zenml-purple-lighter);
        color: var(--zenml-purple);
        border: 1px solid var(--zenml-purple-light);
      }

      .message.error {
        background: var(--error-light);
        color: var(--error);
        border: 1px solid var(--error);
      }

      /* ===== Result Display ===== */
      .result {
        margin-top: var(--spacing-lg);
        padding: var(--spacing-lg);
        border: 1px solid var(--border-moderate);
        border-radius: var(--radius-md);
        background: var(--surface-secondary);
        white-space: normal;
      }

      .result:empty {
        display: none;
      }

      /* Markdown content styling */
      .result h1,
      .result h2,
      .result h3 {
        color: var(--text-primary);
        margin: var(--spacing-md) 0 var(--spacing-sm);
        font-weight: 600;
      }

      .result h1 {
        font-size: 24px;
        line-height: 32px;
      }

      .result h2 {
        font-size: 20px;
        line-height: 28px;
      }

      .result h3 {
        font-size: 16px;
        line-height: 24px;
      }

      .result p {
        margin: var(--spacing-sm) 0;
        line-height: 1.6;
        color: var(--text-primary);
      }

      .result ul {
        padding-left: 20px;
        margin: var(--spacing-sm) 0;
      }

      .result li {
        margin: var(--spacing-xs) 0;
        color: var(--text-primary);
      }

      .result code {
        background: var(--surface-tertiary);
        padding: 2px 6px;
        border-radius: var(--radius-sm);
        font-family: var(--font-mono);
        font-size: 13px;
        color: var(--zenml-purple);
      }

      /* ===== Footer ===== */
      .footer {
        text-align: center;
        padding: var(--spacing-lg);
        background: var(--surface-secondary);
        color: var(--text-secondary);
        font-size: 14px;
        line-height: 20px;
        border-top: 1px solid var(--border-moderate);
        margin: var(--spacing-lg) calc(var(--spacing-lg) * -1)
          calc(var(--spacing-lg) * -1);
        border-radius: 0 0 var(--radius-md) var(--radius-md);
      }

      .footer strong {
        color: var(--zenml-purple);
        font-weight: 600;
      }

      /* ===== Responsive ===== */
      @media (max-width: 768px) {
        body {
          padding: var(--spacing-md);
        }

        .hero {
          flex-direction: column;
          align-items: flex-start;
        }

        .hero-art {
          width: 100%;
          display: flex;
          justify-content: center;
        }

        .actions {
          flex-direction: column;
          align-items: stretch;
        }

        .btn {
          width: 100%;
        }
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="card">
        <!-- Hero Section -->
        <div class="hero">
          <div class="hero-copy">
            <h1 class="title">OpenAI Agents Travel Assistant</h1>
            <p class="subtitle">
              Ask free‑form travel questions—fun facts, quick weather checks, and city info—powered by the OpenAI Agents SDK.
            </p>
          </div>
          <div class="hero-art" aria-hidden="true">
            <!-- Travel-themed illustration (globe + plane) with ZenML purple -->
            <svg width="140" height="100" viewBox="0 0 140 100" xmlns="http://www.w3.org/2000/svg">
              <defs>
                <linearGradient id="skyGradient" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" stop-color="#cab2fb" />
                  <stop offset="100%" stop-color="#f1ebfe" />
                </linearGradient>
              </defs>
              <rect x="0" y="0" width="140" height="100" rx="12" fill="url(#skyGradient)" />
              <!-- Globe -->
              <circle cx="55" cy="55" r="26" fill="#e5e7eb" stroke="#7a3ef4" stroke-width="1.5" />
              <path d="M31 55h48M55 31v48M38 44c10 6 24 6 34 0M38 66c10-6 24-6 34 0" stroke="#7a3ef4" stroke-width="1" fill="none"/>
              <!-- Plane -->
              <g transform="translate(85,35)">
                <path d="M0 8 l28 -4 l0 8 l-28 -4 z" fill="#7a3ef4" />
                <path d="M8 4 l-6 -6 l-2 1 l4 7" fill="#7a3ef4" />
                <path d="M8 12 l-6 6 l-2 -1 l4 -7" fill="#7a3ef4" />
                <circle cx="24" cy="9" r="2" fill="#e5e7eb"/>
              </g>
              <!-- Dotted path -->
              <path d="M70 55c8-10 22-16 36-16" stroke="#9565f6" stroke-width="1.5" stroke-dasharray="3 3" fill="none"/>
            </svg>
          </div>
        </div>

        <!-- Form Section -->
        <div class="section">
          <h2>Try it</h2>
          <div class="form-col">
            <textarea
              id="query-input"
              class="input"
              rows="5"
              placeholder="Examples:&#10;- Tell me a fun fact about Tokyo&#10;- What's the weather like in Paris?&#10;- Share some highlights of London"
            ></textarea>

            <!-- Suggestion Chips -->
            <div class="chips" id="suggestion-chips" aria-label="Example queries">
              <span class="chip" data-query="Tell me a fun fact about Tokyo">Fun fact: Tokyo</span>
              <span class="chip" data-query="What's the weather in Paris?">Weather: Paris</span>
              <span class="chip" data-query="What is New York City famous for?">NYC highlights</span>
              <span class="chip" data-query="Give me some quick facts about London">Quick facts: London</span>
              <span class="chip" data-query="What should I know before visiting Berlin?">Tips: Berlin</span>
            </div>

            <div class="actions">
              <button id="ask-btn" class="btn">Ask Assistant</button>
              <button id="set-key-btn" class="btn secondary" style="display: none">Set API Key</button>
              <div id="auth-status" class="status-pill auth-required" style="display: none">Auth required</div>
            </div>
          </div>

          <div id="message" class="message"></div>

          <!-- Result Display -->
          <div id="result" class="result"></div>
        </div>

        <!-- Footer -->
        <div class="footer">
          Powered by <strong>ZenML</strong> Pipeline Deployments | Real-time inference
        </div>
      </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.7/dist/purify.min.js"></script>
    <script>
      // Configure markdown rendering for conversational responses
      if (typeof marked !== 'undefined' && typeof marked.setOptions === 'function') {
        marked.setOptions({ gfm: true, breaks: true });
      }

      // Templated by ZenML deployment
      const INVOKE_URL = "{{ service_info.app.invoke_url_path }}";
      const AUTH_ENABLED = "{{ 'true' if service_info.deployment.auth_enabled else 'false' }}" === 'true';

      // UI Elements
      const queryInput = document.getElementById('query-input');
      const askBtn = document.getElementById('ask-btn');
      const messageEl = document.getElementById('message');
      const resultEl = document.getElementById('result');
      const setKeyBtn = document.getElementById('set-key-btn');
      const authStatus = document.getElementById('auth-status');
      const chips = document.getElementById('suggestion-chips');

      // Local storage key for bearer token (per-example)
      const API_KEY_STORAGE = 'travel_assistant_api_key';

      function setLoading(isLoading) {
        askBtn.disabled = isLoading;
        askBtn.textContent = isLoading ? 'Asking…' : 'Ask Assistant';
        if (isLoading) {
          messageEl.textContent = 'Contacting the Travel Assistant...';
          messageEl.className = 'message info';
        }
      }

      function showError(text) {
        messageEl.textContent = text;
        messageEl.className = 'message error';
      }

      function clearMessage() {
        messageEl.textContent = '';
        messageEl.className = 'message';
      }

      function getApiKey() {
        return localStorage.getItem(API_KEY_STORAGE);
      }

      function updateAuthStatus() {
        if (!AUTH_ENABLED) return;
        const hasKey = !!getApiKey();
        authStatus.textContent = hasKey ? 'API key set' : 'Auth required';
        authStatus.style.background = hasKey ? '#ecfdf5' : '#fff6ea';
        authStatus.style.color = hasKey ? '#065f46' : '#f98b0a';
        setKeyBtn.textContent = hasKey ? 'Update API Key' : 'Set API Key';
      }

      async function promptForApiKey() {
        const current = getApiKey() || '';
        const entered = prompt('Enter API Key (Bearer token):', current ? '********' : '');
        if (entered === null) return; // canceled
        if (entered === '********') return; // keep existing
        const trimmed = (entered || '').trim();
        if (!trimmed) {
          localStorage.removeItem(API_KEY_STORAGE);
        } else {
          localStorage.setItem(API_KEY_STORAGE, trimmed);
        }
        updateAuthStatus();
      }

      function initAuthUI() {
        if (!AUTH_ENABLED) return;
        setKeyBtn.style.display = '';
        authStatus.style.display = '';
        updateAuthStatus();
        setKeyBtn.addEventListener('click', promptForApiKey);
      }

      // Handle suggestion chips click-to-fill
      function initChips() {
        if (!chips) return;
        chips.addEventListener('click', (e) => {
          const el = e.target;
          if (!(el instanceof HTMLElement)) return;
          const q = el.getAttribute('data-query');
          if (!q) return;
          queryInput.value = q;
          queryInput.focus();
        });
      }

      // Main invoke handler
      async function askAssistant() {
        const query = queryInput.value.trim();
        if (!query) {
          showError('Please enter a question or prompt.');
          return;
        }

        if (AUTH_ENABLED && !getApiKey()) {
          await promptForApiKey();
          if (!getApiKey()) {
            showError('API key is required to call the service.');
            return;
          }
        }

        setLoading(true);
        resultEl.innerHTML = '';
        try {
          const headers = { 'Content-Type': 'application/json' };
          const key = getApiKey();
          if (AUTH_ENABLED && key) headers['Authorization'] = `Bearer ${key}`;

          const res = await fetch(INVOKE_URL, {
            method: 'POST',
            headers,
            body: JSON.stringify({ parameters: { query: query } }),
          });

          if (!res.ok) {
            const text = await res.text();
            throw new Error('Request failed: ' + res.status + ' ' + text);
          }

          const data = await res.json();
          if (!data.success) {
            const err = data.error || 'Unknown error from service.';
            throw new Error(err);
          }

          const outputs = data.outputs || {};
          // The pipeline returns a single string artifact named "formatted_response"
          let md = outputs.formatted_response;

          // Fallbacks for robustness if naming differs
          if (!md && typeof outputs === 'string') md = outputs;
          if (!md && outputs.response) md = outputs.response;

          if (!md) {
            messageEl.textContent = 'No response returned.';
            messageEl.className = 'message info';
            return;
          }

          const html = marked.parse(md);
          resultEl.innerHTML = DOMPurify.sanitize(html);
          clearMessage();
        } catch (e) {
          showError(e.message || String(e));
        } finally {
          setLoading(false);
        }
      }

      // Event wiring
      askBtn.addEventListener('click', askAssistant);
      // Support Cmd/Ctrl+Enter for quick submit
      queryInput.addEventListener('keydown', function (e) {
        if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
          askAssistant();
        }
      });

      // Initialize UI
      initAuthUI();
      initChips();
    </script>
  </body>
</html>
